Repository navigation
nvx-rs: add a guest mapping API with explicit export and target roots - #652
Merged
Pedro Henrique Penna (ppenna) merged 2 commits intoOct 21, 2026
Merged
Pedro Henrique Penna (ppenna) merged 2 commits into
Pedro Henrique Penna (ppenna) merged 2 commits into
Conversation
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No blocking issues were identified; the extraction preserves existing mapping behavior and adds focused regression coverage.
No open issues 🎉
What changed in this PR
Exposes host mapping operations as a reusable guest library, advancing #619 while preserving managed-agent behavior.
Changes:
- Adds explicit export and target roots, path validation, and staged errors.
- Migrates the managed agent to the library and adds regression tests.
- Documents the public mapping API.
| File | Description |
|---|---|
nvx-rs/src/lib.rs |
Introduces the mapping library in crate documentation. |
nvx-rs/src/guest/mod.rs |
Exports and documents mappings. |
nvx-rs/src/guest/mappings.rs |
Implements the public API and focused tests. |
nvx-rs/src/guest/managed_agent/mappings.rs |
Uses the library while preserving sequencing and failure handling. |
nvx-rs/README.md |
Documents mapping APIs and agent integration. |
doc/project-structure.md |
Adds the library to the repository overview. |
Review effort: Balanced
Enrique Saurez (esaurez)
marked this pull request as ready for review
October 20, 2026 19:37
Enrique Saurez (esaurez)
force-pushed
the
esaurez/a1-guest-g4-mapping-roots-20261020
branch
from
October 21, 2026 00:58
ed2ba4f to
89d4400
Compare
This was referenced Oct 21, 2026
Enrique Saurez (esaurez)
requested a review
from Pedro Henrique Penna (ppenna)
October 21, 2026 16:09
The managed agent applied each decoded host mapping against two implicit roots: its mount of the host's export, and absolute targets in its own root. nvx::guest::mappings makes both explicit for any guest init or agent. A Mapping holds a relative source below the export root, a target that is absolute as seen from the target root, and its access, and refuses empty, `.`, and `..` components, so that each path stays below its root. Mapping::apply takes both roots. It keeps the agent's rules: a directory source gets a directory target, a regular-file source gets a regular-file target that it creates without following a symbolic link, any other source is refused, and every bind is remounted nosuid and nodev, and read-only when asked. A failure reports its stage and errno. The managed agent passes hostfs_dir/root as the export root and / as the target root, so its behavior is unchanged, and keeps the count that the kernel command line announces, the order of MAPS batches, and the latch after a failure. Part of #619. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7f9f821d-e550-4890-b672-8aaad5b45b0c
Enrique Saurez (esaurez)
force-pushed
the
esaurez/a1-guest-g4-mapping-roots-20261020
branch
from
October 21, 2026 16:26
89d4400 to
f70adb9
Compare
Pedro Henrique Penna (ppenna)
left a comment
Contributor
There was a problem hiding this comment.
Left some questions.
A Mapping keeps its target relative to the target root: Mapping::new strips the leading `/` once, after validation proves it, so applying a mapping needs no expect. MAX_PATH_BYTES derives from Linux's PATH_MAX, which guest::sys now names, and the modes of the directories and files that a mapping creates are named constants. The adapter documents the decoder's bounds on the paths that it converts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7f9f821d-e550-4890-b672-8aaad5b45b0c
Pedro Henrique Penna (ppenna)
approved these changes
Oct 21, 2026
Pedro Henrique Penna (ppenna)
enabled auto-merge
October 21, 2026 22:00
Pedro Henrique Penna (ppenna)
disabled auto-merge
October 21, 2026 22:01
Pedro Henrique Penna (ppenna)
deleted the
esaurez/a1-guest-g4-mapping-roots-20261020
branch
October 21, 2026 22:01
This was referenced Oct 21, 2026
Closed
This was referenced Oct 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A guest init or agent can now apply decoded host mapping entries against roots that it names, through public APIs: an export root, where the host's shares appear, and a target root, the tree that the mappings go into. Until now the managed agent applied them against two implicit roots: its mount of the host's export, and absolute targets in its own root.
Part of #619 (step G4). Refs #535.
What changed
nvx::guest::mappings, new under theguestfeature:Mapping::new(source, target, access)takes a source relative to the export root, a target that is absolute as seen from the target root, and anAccess,ReadOnlyorReadWrite. It refuses a path of more thanMAX_PATH_BYTESbytes, Linux'sPATH_MAXwithout its terminating NUL, with a NUL byte, or with an empty,., or..component, so that each path stays below its root, andInvalidMappingsays which one. These are the MAPS decoder's rules, so every entry that the decoder accepts converts. AMappingkeeps its target relative to the target root, without the leading/, whichtarget()returns.Mapping::apply(export_root, target_root)takes both roots explicitly, as absolute paths. It keeps the managed agent's rules:O_CREAT | O_EXCL | O_NOFOLLOW;EINVAL;nosuid,nodev, androwhen it is read-only.MappingFailurewith itsMappingStage(source, target, bind or remount) anderrno, and leaves what the earlier stages did.guest/managed_agent/mappings.rs) converts each decoded MAPS entry into aMapping, and applies it withhostfs_dir/rootas the export root and/as the target root, through its system seam's mount. Its mount calls, their bytes and its errors are unchanged. It keeps the count announced on/proc/cmdline, the order of MAPS batches, and the latch after a failed mapping. The dispatcher is unchanged.guestmodule and README documentation, anddoc/project-structure.md, name the library.tests/runtime-adapterdoesn't call the API yet; a later A1-guest step does.devhas no public-API snapshot check, so there is no snapshot to update.Tests
/, which create nothing outside the target root;Sizes
Static
x86_64-unknown-linux-muslguest profile, built withbuild-guest-binariesand the Alpinebuild-initramfs, natively in WSL Ubuntu with Rust 1.95.0, fordevat5f189bdband this head:nvx-managed-agent, stripped.textgrows from 365,598 to 367,086 bytes, and the other sections by 344 bytes in all, within the existing alignment paddinginitramfs.cpio.gzValidation
On this head, rebased onto
devat5f189bdb, on Windows 11 with WHP and in WSL Ubuntu with KVM, except where a run namesf70adb95, this head before its review fixes:python scripts/nvx.py verifyandpython scripts/check_markdown_links.py.check-nvx-rs, innvx-rs, withNVX_BUNDLE=skip:cargo fmt --all --check;cargo clippy --locked --all-targets --all-features -- -D warnings;cargo clippy --locked --lib --no-default-features -- -D warnings;cargo test --locked --all-features;cargo test --locked; the artifact-bundling test against a synthetic release;cargo doc --locked --no-deps --all-featureswith-D warnings; the 1.89 MSRV check; and theaarch64-apple-darwincheck. As root, the caller-owned-share scenarios oftests/cli.rsfail, because they refuse a share that UID 0 owns, as they do ondev; with--no-fail-fasteverything else passes.python3 scripts/nvx.py check-guest-binaries, thenbuild-guest-binaries --output <dir>andtest-guest-binaries --binaries <dir>.tests/runtime-adapterin its protocol-only, host-only, and musl guest-only configurations: rustfmt, Clippy, the build, the tests, and the MSRV check.check-aci-edge-sandboxes: rustfmt, Clippy, the tests with all and with default features,test-agent-bundling, the documentation, the MSRV check, and theaarch64-apple-darwincheck.nvx-managed-agentI checked by digest, thenvx-rsCLI built from it, and the kernel and OpenVMM of releasev0.1.0-dev.d9859648556a, whose OpenVMM is the pinnedd0bdbed8:python scripts/nvx.py test-aci-edge-sandboxes --backend whppassed all 18 cases. Six of them map host directories and files into the guest; the seventh, which maps a directory on a second volume, returns early because this host's temporary directory has none.python scripts/nvx.py test-microvm --backend whp --scenario managed-lifecycle --scenario managed-exec-config --scenario sandbox-lifecyclepassed. Onf70adb95, the whole default suite on 1, 2, 4, and 8 processors passed too.f70adb95: on this Alder Lake host,--cpu-profile autoselects a built-in profile that needs MSR bits that WSL's KVM doesn't expose, so OpenVMM ran through a local wrapper that adds--cpu-profile host.test-microvm --backend kvm --processors 1passedguest-boot,lifecycle,managed-lifecycle,filesystem-shares,filesystem-policy,filesystem-comma-paths,filesystem-owner,denied-filesystem-paths, andfilesystem-snapshot, thenmanaged-exec-configandsandbox-lifecycle.test-aci-edge-sandboxes --backend kvmpassed 13 of 18 cases. The 5 that write into read-write mappings fail withPermission denied, because the host side runs as root in WSL; withdev's agent, the initramfs of5f189bdb, the same 5 fail in the same way.